/** * KKS Videos — embed loader (estilo VTurb, uma linha) * * Novo (recomendado): * * * * Legado (continua funcionando): *
* */ (function () { 'use strict'; var SCRIPT_EL = document.currentScript; var EMBED_BASE = ''; var EMBED_VERSION = '1'; if (SCRIPT_EL && SCRIPT_EL.src) { EMBED_BASE = SCRIPT_EL.src.replace(/\/embed\.js(\?.*)?$/, ''); try { EMBED_VERSION = new URL(SCRIPT_EL.src).searchParams.get('v') || '1'; } catch (e) {} } function loadScript(src) { return new Promise(function (resolve, reject) { var existing = document.querySelector('script[src="' + src + '"]'); if (existing && existing.getAttribute('data-kks-loaded') === '1') { resolve(); return; } var s = document.createElement('script'); s.src = src; s.async = false; s.onload = function () { s.setAttribute('data-kks-loaded', '1'); resolve(); }; s.onerror = function () { reject(new Error('Falha ao carregar: ' + src)); }; document.head.appendChild(s); }); } function loadCss(href) { if (document.querySelector('link[href="' + href + '"]')) return; var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = href; document.head.appendChild(l); } function getBase() { if (EMBED_BASE) { return EMBED_BASE; } var script = document.currentScript; if (!script) { var scripts = document.getElementsByTagName('script'); for (var i = scripts.length - 1; i >= 0; i--) { if (scripts[i].src && /embed\.js/.test(scripts[i].src)) { script = scripts[i]; break; } } } if (script && script.src) { return script.src.replace(/\/embed\.js(\?.*)?$/, ''); } return ''; } function getApiBase(publicBase) { return publicBase.replace(/\/public\/?$/, '') + '/api'; } function markLoading(node) { node.classList.add('kks-embed-loading'); } function getEmbedId(node) { return (node.getAttribute('embed') || node.getAttribute('data-embed') || '').trim(); } function getHead() { return document.head || document.getElementsByTagName('head')[0] || null; } function originOf(url) { try { return new URL(url, window.location.href).origin; } catch (e) { return ''; } } /** dns-prefetch + preconnect — acelera conexão com CDN/host do stream. */ function warmConnection(url) { var head = getHead(); var origin = originOf(url); if (!head || !origin) return; if (!document.querySelector('link[rel="dns-prefetch"][href="' + origin + '"]')) { var dns = document.createElement('link'); dns.rel = 'dns-prefetch'; dns.href = origin; head.appendChild(dns); } if (!document.querySelector('link[rel="preconnect"][href="' + origin + '"]')) { var pre = document.createElement('link'); pre.rel = 'preconnect'; pre.href = origin; pre.crossOrigin = 'anonymous'; head.appendChild(pre); } } /** Safari iOS com HLS nativo — igual VTurb: preload do master .m3u8. */ function isAppleMobileNativeHls() { var ua = (navigator && navigator.userAgent) || ''; var vendor = (navigator && navigator.vendor) || ''; var mobile = /mobile/i.test(ua); var apple = vendor.indexOf('Apple') > -1 && ua.indexOf('CriOS') === -1 && ua.indexOf('FxiOS') === -1; if (!(apple && mobile)) return false; try { return document.createElement('video').canPlayType('application/vnd.apple.mpegURL') !== ''; } catch (e) { return false; } } function preloadHlsManifest(streamUrl) { if (!streamUrl) return; warmConnection(streamUrl); if (!isAppleMobileNativeHls()) return; var head = getHead(); if (!head) return; if (document.querySelector('link[rel="preload"][href="' + streamUrl + '"]')) return; var link = document.createElement('link'); link.rel = 'preload'; link.href = streamUrl; link.setAttribute('as', 'fetch'); link.setAttribute('crossorigin', 'anonymous'); head.appendChild(link); } /** Aceita e o formato antigo div[data-embed]. */ function findEmbedNodes() { var nodes = []; var seen = []; function pushUnique(node) { if (seen.indexOf(node) !== -1) return; seen.push(node); nodes.push(node); } document.querySelectorAll('kks-player').forEach(pushUnique); document.querySelectorAll('[data-embed]').forEach(function (node) { if (node.tagName && node.tagName.toLowerCase() === 'kks-player') return; pushUnique(node); }); return nodes; } function hasEmbedNodes() { return findEmbedNodes().length > 0; } /** Prefere a versão do servidor (assetVersion); landing ?v= ainda força se for mais nova. */ function resolveAssetVersion(serverVersion) { var a = parseInt(String(serverVersion || ''), 10); var b = parseInt(String(EMBED_VERSION || ''), 10); if (!isNaN(a) && !isNaN(b)) return String(Math.max(a, b)); if (!isNaN(a)) return String(a); if (!isNaN(b)) return String(b); return String(serverVersion || EMBED_VERSION || '1'); } function boot() { var base = getBase(); if (!base) { console.error('[KKS Embed] Não foi possível detectar a URL base do embed.js'); return; } var configBase = getApiBase(base) + '/vsl-config.php'; var hlsUrl = 'https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js'; // Aquecimento precoce: HLS lib, painel/API e assets do player warmConnection(hlsUrl); warmConnection(base); warmConnection(configBase); var nodes = findEmbedNodes(); if (nodes.length === 0) { console.warn('[KKS Embed] Nenhum ou [data-embed] encontrado.'); return; } nodes.forEach(markLoading); loadScript(hlsUrl).then(function () { var embedIds = []; nodes.forEach(function (node, index) { var embedId = getEmbedId(node); if (!embedId) return; if (!node.id) { node.id = nodes.length === 1 ? 'vsl-player' : 'vsl-player-' + index; } embedIds.push({ node: node, id: embedId }); }); var assetVersion = EMBED_VERSION; var chain = Promise.resolve(); embedIds.forEach(function (item) { chain = chain.then(function () { return loadScript(configBase + '?embed_id=' + encodeURIComponent(item.id)); }).then(function () { if (window.VSL_CONFIG) { window.VSL_CONFIG.containerId = item.node.id; if (window.VSL_CONFIG.assetVersion) { assetVersion = resolveAssetVersion(window.VSL_CONFIG.assetVersion); } // Depois da config: prefetch/preload do host do .m3u8 (CloudFront/S3/domínio do cliente) preloadHlsManifest(window.VSL_CONFIG.streamUrl || ''); } }); }); return chain.then(function () { var ver = encodeURIComponent(assetVersion); loadCss(base + '/vsl/player.css?v=' + ver); return loadScript(base + '/vsl/player.js?v=' + ver); }); }).catch(function (err) { console.error('[KKS Embed] Falha ao carregar player:', err); }); } function start() { if (hasEmbedNodes()) { boot(); return; } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } } start(); })();